#include "NUC100Series.h"
#include <gpio.h>
#include "uda1341.h"

uint32_t g_u32TxValue;

/*
 * @brief This function provides the configured MFP registers
 * @param None
 * @return None
 */
void GPIO_INIT_I2S(void)
{
    //SYS->ALT_MFP = 0x000003E0UL;
    //SYS->ALT_MFP1 = 0x00000000UL;
    //SYS->GPA_MFP = 0x00008000UL;
    //SYS->GPB_MFP = 0x00000000UL;
    //SYS->GPC_MFP = 0x0000000FUL;
    //SYS->GPE_MFP = 0x00000000UL;

    /* If the macros do not exist in your project, please refer to the corresponding header file in Header folder of the tool package */
    SYS->ALT_MFP = SYS_ALT_MFP_PC3_I2S_DO | SYS_ALT_MFP_PC2_I2S_DI | SYS_ALT_MFP_PC1_I2S_BCLK | SYS_ALT_MFP_PC0_I2S_LRCLK | SYS_ALT_MFP_PA15_I2S_MCLK;
    SYS->ALT_MFP1 = 0x00000000;
    SYS->GPA_MFP = SYS_GPA_MFP_PA15_I2S_MCLK;
    SYS->GPB_MFP = 0x00000000;
    SYS->GPC_MFP = SYS_GPC_MFP_PC3_I2S_DO | SYS_GPC_MFP_PC2_I2S_DI | SYS_GPC_MFP_PC1_I2S_BCLK | SYS_GPC_MFP_PC0_I2S_LRCLK;
    SYS->GPE_MFP = 0x00000000;

    return;
}

void MyProject_init_ebi(void)
{
    CLK_EnableModuleClock(EBI_MODULE);

    return;
}

void MyProject_deinit_ebi(void)
{
    CLK_DisableModuleClock(EBI_MODULE);

    return;
}

void MyProject_init_i2s(void)
{
    CLK_EnableModuleClock(I2S_MODULE);
    CLK_SetModuleClock(I2S_MODULE, CLK_CLKSEL2_I2S_S_HCLK, MODULE_NoMsk);

    return;
}

void MyProject_deinit_i2s(void)
{
    CLK_DisableModuleClock(I2S_MODULE);

    return;
}

void MyProject_init_isp(void)
{
    CLK_EnableModuleClock(ISP_MODULE);

    return;
}

void MyProject_deinit_isp(void)
{
    CLK_DisableModuleClock(ISP_MODULE);

    return;
}

void MyProject_init_systick(void)
{
    CLK_EnableSysTick(CLK_CLKSEL0_STCLK_S_HIRC_DIV2, 0);

    return;
}

void MyProject_deinit_systick(void)
{
    CLK_DisableSysTick();

    return;
}

void MyProject_init_base(void)
{
    /* If the macros do not exist in your project, please refer to the related clk.h in Header folder of the tool package */
    /* Enable clock source */
    CLK_EnableXtalRC(CLK_PWRCON_OSC22M_EN_Msk);

    /* Waiting for clock source ready */
    CLK_WaitClockReady(CLK_CLKSTATUS_OSC22M_STB_Msk);

    /* Set HCLK clock */
    CLK_SetHCLK(CLK_CLKSEL0_HCLK_S_HIRC, CLK_CLKDIV_HCLK(1));

    return;
}

void MyProject_init(void)
{
    /*---------------------------------------------------------------------------------------------------------*/
    /* Init System Clock                                                                                       */
    /*---------------------------------------------------------------------------------------------------------*/
    //CLK->PWRCON   = (CLK->PWRCON   & ~(0x0000000FUL)) | 0x00000014UL;
    //CLK->PLLCON   = (CLK->PLLCON   & ~(0x000FFFFFUL)) | 0x0005C22EUL;
    //CLK->CLKDIV   = (CLK->CLKDIV   & ~(0x00FF0FFFUL)) | 0x00000000UL;
    //CLK->CLKDIV1  = (CLK->CLKDIV1  & ~(0x00FFFFFFUL)) | 0x00000000UL;
    //CLK->CLKSEL0  = (CLK->CLKSEL0  & ~(0x0000003FUL)) | 0x0000003FUL;
    //CLK->CLKSEL1  = (CLK->CLKSEL1  & ~(0xF37777FFUL)) | 0xFFFFFFFFUL;
    //CLK->CLKSEL2  = (CLK->CLKSEL2  & ~(0x00030FFFUL)) | 0x000200FEUL;
    //CLK->CLKSEL3  = (CLK->CLKSEL3  & ~(0x0000003FUL)) | 0x0000003FUL;
    //CLK->AHBCLK   = (CLK->AHBCLK   & ~(0x0000000EUL)) | 0x0000000DUL;
    //CLK->APBCLK   = (CLK->APBCLK   & ~(0xF8F7F37FUL)) | 0x20000000UL;
    //CLK->APBCLK1  = (CLK->APBCLK1  & ~(0x00000007UL)) | 0x00000000UL;
    //CLK->FRQDIV   = (CLK->FRQDIV   & ~(0x0000001FUL)) | 0x00000000UL;
    //SysTick->CTRL = (SysTick->CTRL & ~(0x00000005UL)) | 0x00000001UL;

    /* Unlock protected registers */
    SYS_UnlockReg();

    /* Enable base clock */
    MyProject_init_base();

    /* Enable module clock and set clock source */
    MyProject_init_ebi();
    MyProject_init_i2s();
    MyProject_init_isp();
    MyProject_init_systick();

    /* Update System Core Clock */
    /* User can use SystemCoreClockUpdate() to calculate SystemCoreClock. */
    SystemCoreClockUpdate();

    /* Lock protected registers */
    SYS_LockReg();

    return;
}

void I2S_IRQHandler()
{
    /* Write 4 Tx values to TX FIFO */
    I2S_WRITE_TX_FIFO(I2S, g_u32TxValue);
    I2S_WRITE_TX_FIFO(I2S, g_u32TxValue);
    I2S_WRITE_TX_FIFO(I2S, g_u32TxValue);
    I2S_WRITE_TX_FIFO(I2S, g_u32TxValue);
}

int main(){
	uint32_t u32DataCount, u32RxValue1, u32RxValue2;	
	
	MyProject_init();
	GPIO_INIT_I2S();
	read_data(UDA1341_REG_DATA1);
	set_data(UDA1341_REG_STATUS,STAT0_SC_256FS|STAT0_IF_I2S|STAT0_DC_FILTER);	
	set_data(UDA1341_REG_DATA0,DATA0_VOLUME(0) & DATA0_VOLUME_MASK);

	I2S_Open(I2S,I2S_MODE_MASTER, 8000, I2S_DATABIT_16, I2S_STEREO, I2S_FORMAT_I2S);
	I2S_EnableMCLK(I2S,256*8000);

	NVIC_EnableIRQ(I2S_IRQn);

	/* Initiate data counter */
	u32DataCount = 0;
	/* Initiate Tx value and Rx value */
	g_u32TxValue = 0x0;
	u32RxValue1 = 0;
	u32RxValue2 = 0;
	/* Enable Tx threshold level interrupt */
	I2S_EnableInt(I2S, I2S_IE_TXTHIE_Msk);

	while(1){
        if((I2S->STATUS & I2S_STATUS_RXEMPTY_Msk) == 0)
        {
            u32DataCount++;
						
            if(u32DataCount >= 1000)
            {
                g_u32TxValue =  0x0; /* g_u32TxValue: 0x55005501, 0x55025503, ..., 0x55FE55FF */
                u32DataCount = 0;
            }else{
							g_u32TxValue += 0x11223344;
						}
        }
	}
	return 0;
}